package net.web.belerofont.controller;

import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.web.belerofont.action.Action;
import net.web.belerofont.action.Interceptor;
import net.web.belerofont.action.URIMap;
import net.web.belerofont.action.support.URIMapSupport;
import net.web.belerofont.annotation.Forward;
import net.web.belerofont.annotation.Logic;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AssignableTypeFilter;

public class ConfigAnotationReader extends ConfigReader {
	public static final Logger LOG = Logger.getLogger(ConfigReader.class);
	
	ConfigReader config;
	private Map<String, Action> actionMap;
	private List<Interceptor> globalInterceptorsList;
	private Map<String, List<Interceptor>> localInterceptorsMap;

	@SuppressWarnings("unchecked")
	public ConfigAnotationReader(ConfigReader reader) throws CreateConfigException {
		Action localAction = null;
		URIMap localURIMap;

		try {
			this.config = reader;
			
			actionMap = this.config.getActions();
			
			globalInterceptorsList = this.config.getGlobalInterceptors();
			
			localInterceptorsMap = new HashMap<String, List<Interceptor>>();
			
			ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(
					true);
			provider.addIncludeFilter(new AssignableTypeFilter(Action.class));
	
			Set<BeanDefinition> components = provider
					.findCandidateComponents("");
			
			for (BeanDefinition component : components) {
				Class classLogic = Class.forName(component.getBeanClassName());
				for (Annotation annotation: classLogic.getAnnotations()) {
					if (annotation instanceof Logic) {
						Logic logic = (Logic) annotation;
						if (actionMap.get(logic.path()) != null) break; 

						localAction = getActionByClassName(classLogic.getCanonicalName());
						
						this.actionMap.put(logic.path(),
								localAction);

						LOG.debug("Action: " + logic.path());
						
						LOG.debug("Forwards:");
						Map<String, URIMap> uris = new HashMap<String, URIMap>();
						for(Forward forward : logic.forwards()) {
							localURIMap = URIMapSupport.instance(forward.path(), forward.transferType());
							uris.put(forward.name(),localURIMap);
							LOG.debug("\t" + forward.name() + "::"
									+ forward.path());
						}
						localAction.init(uris);
						
						LOG.debug("Interceptors:");
						List<Interceptor> localInterceptors = new LinkedList<Interceptor>();

						for(net.web.belerofont.annotation.Interceptor interceptor : logic.interceptors()) {
							localInterceptors.add(getInterceptorByClassName(interceptor.className()));
							
							LOG.debug("\t" + interceptor.className());
						}
						
						this.localInterceptorsMap.put(logic.path(), localInterceptors);
						
						break;
					}
				}
			}
		} catch (Exception ex) {
			throw new CreateConfigException(ex);
		}
	}


	public Map<String, Action> getActions() {
		return actionMap;
	}

	public List<Interceptor> getGlobalInterceptors() {
		return globalInterceptorsList;
	}

	public List<Interceptor> getInterceptors(String actionPath) {
		List<Interceptor> list = new LinkedList<Interceptor>();
		list.addAll(globalInterceptorsList);
		
		List<Interceptor> listLocal = getLocalInterceptors(actionPath); 
		if (listLocal != null) list.addAll(listLocal);
		
		return list;
	}

	public List<Interceptor> getLocalInterceptors(String actionPath) {
		if (this.config.getLocalInterceptors(actionPath) != null) {
			return this.config.getLocalInterceptors(actionPath);
		} else {
			return localInterceptorsMap.get(actionPath);
		}
	}
}
